package com.link2room.rodimus.service.impl;

import com.link2room.common.constant.DefaultValue;
import com.link2room.common.dao.ICommonDao;
import com.link2room.common.exception.SysException;
import com.link2room.common.mns.MNSUtil;
import com.link2room.common.service.ICommonService;
import com.link2room.common.util.DateUtil;
import com.link2room.common.util.JacksonUtil;
import com.link2room.rodimus.constant.GroupBuyingConstant;
import com.link2room.rodimus.constant.MallOrderConstant;
import com.link2room.rodimus.dto.param.base.GroupBuyingAutoCancelParamDto;
import com.link2room.rodimus.dto.param.base.GroupBuyingAutoRefundParamDto;
import com.link2room.rodimus.entity.*;
import com.link2room.rodimus.service.IGroupBuyingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

import static com.link2room.enums.exception.RodimusSysExceptionEnum.GENERATE_TEAMNO_ERROR;
import static com.link2room.enums.exception.RodimusSysExceptionEnum.TEAMAUTO_CANCEL_ERROR;
import static com.link2room.rodimus.constant.RodimusMnsConstant.QUEUE_GROUPBUYING_AUTO_CANCEL;
import static com.link2room.rodimus.constant.RodimusMnsConstant.QUEUE_GROUPBUYING_AUTO_REFUND;

/**
 * Created by LN on 2017/12/6
 */
@Component("groupBuyingService")
public class GroupBuyingServiceImpl implements IGroupBuyingService {
    @Autowired
    private RedisLockRegistry createGroupBuyingTeamNoLock;
    @Autowired
    private RedisLockRegistry groupbuyingTeamCodeLock;
    @Resource
    private ICommonService commonService;
    @Resource
    private ICommonDao commonDao;
    @Resource
    private MNSUtil mnsUtil;
    private static final String TEAM_NO = "TEAM_NO";

    @Override
    public String generateTeamNo() throws Exception {
        Lock lock = createGroupBuyingTeamNoLock.obtain(TEAM_NO);

        if (lock.tryLock(3, TimeUnit.SECONDS)) {
            try {
                //0 初始化
                List<MallOrderPrice> mallOrderPrices = new ArrayList<>();
                List params = new ArrayList<>();
                params.add(TEAM_NO);
                return commonService.findOneFieldByProcedure("create_No", params);
            } finally {
                lock.unlock();
            }
        } else {
            throw new SysException(GENERATE_TEAMNO_ERROR, "");
        }
    }

    @Override
    @Transactional
    public void saveTeam(MallOrderBase orderBase, GroupBuyingTeamEntity teamEntity, GroupBuyingTeamDetailEntity captainDetail) throws Exception {
        commonDao.save(teamEntity);
        commonDao.save(captainDetail);
        commonDao.save(orderBase);
    }

    @Override
    @Transactional
    public void joinTeam(MallOrderBase orderBase, GroupBuyingTeamDetailEntity captainDetail) throws Exception {
        commonDao.save(captainDetail);
        commonDao.save(orderBase);
    }

    @Override
    @Transactional
    public void teamAutoCancel(MallOrderBase orderBase) throws Exception {
        orderBase.setSta(MallOrderConstant.Sta.cancel);
        GroupBuyingTeamDetailEntity findTeamDetail = new GroupBuyingTeamDetailEntity();
        findTeamDetail.setOrderNo(orderBase.getOrderCode());
        findTeamDetail.setLhotelGroupCode(orderBase.getLhotelGroupCode());
        findTeamDetail.setOrderNo(orderBase.getOrderCode());
        GroupBuyingTeamDetailEntity teamDetail = commonService.findOneEQ(GroupBuyingTeamDetailEntity.class, findTeamDetail);
        if (null == teamDetail) {
            return;
        }
        String teamCode = teamDetail.getTeamCode();
        Lock lock = groupbuyingTeamCodeLock.obtain(teamCode);
        if (lock.tryLock(5, TimeUnit.SECONDS)) {
            try {
                String isCaptain = teamDetail.getIsCaptain();
                if (DefaultValue.T.equals(isCaptain)) {
                    GroupBuyingTeamEntity findTeam = new GroupBuyingTeamEntity();
                    findTeam.setTeamCode(teamDetail.getTeamCode());
                    GroupBuyingTeamEntity groupbuyingTeam = commonService.findOneEQ(GroupBuyingTeamEntity.class, findTeam);
                    if (null != groupbuyingTeam) {
                        return;
                    }
                    groupbuyingTeam.setSta(GroupBuyingConstant.TEAM_STA.AUTO_CANCEL);
                    teamDetail.setSta(GroupBuyingConstant.TEAM_DETAIL_STA.AUTO_CANCEL);
                    commonDao.merge(orderBase);
                    commonDao.merge(teamDetail);
                    commonDao.merge(groupbuyingTeam);
                } else {
                    teamDetail.setSta(GroupBuyingConstant.TEAM_DETAIL_STA.AUTO_CANCEL);
                    commonDao.merge(orderBase);
                    commonDao.merge(teamDetail);
                }
            } finally {
                lock.unlock();
            }
        } else {
            throw new SysException(TEAMAUTO_CANCEL_ERROR, "当前操作阻塞,稍后重试");
        }

    }

    @Override
    @Transactional
    public void teamPaid(MallOrderBase orderBase) throws Exception {
        orderBase.setSta(MallOrderConstant.Sta.init);

        GroupBuyingTeamDetailEntity findTeamDetail = new GroupBuyingTeamDetailEntity();
        findTeamDetail.setOrderNo(orderBase.getOrderCode());
        findTeamDetail.setLhotelGroupCode(orderBase.getLhotelGroupCode());
        findTeamDetail.setOrderNo(orderBase.getOrderCode());
        GroupBuyingTeamDetailEntity teamDetail = commonService.findOneEQ(GroupBuyingTeamDetailEntity.class, findTeamDetail);
        if (null == teamDetail) {
            return;
        }

        String teamCode = teamDetail.getTeamCode();
        Lock lock = groupbuyingTeamCodeLock.obtain(teamCode);
        String groupBuyingCode = null;

        if (lock.tryLock(30, TimeUnit.SECONDS)) {
            try {
                GroupBuyingTeamEntity findTeam = new GroupBuyingTeamEntity();
                findTeam.setTeamCode(teamDetail.getTeamCode());
                GroupBuyingTeamEntity groupbuyingTeam = commonService.findOneEQ(GroupBuyingTeamEntity.class, findTeam);
                if (null == groupbuyingTeam) {
                    return;
                }
                groupBuyingCode = groupbuyingTeam.getGroupBuyingCode();
                GroupBuyingBaseEntity findBase = new GroupBuyingBaseEntity();
                findBase.setCode(groupBuyingCode);

                String isCaptain = teamDetail.getIsCaptain();
                teamDetail.setSta(GroupBuyingConstant.TEAM_DETAIL_STA.PAID);
                if (DefaultValue.T.equals(isCaptain)) {

                    GroupBuyingBaseEntity groupBuyingBase = commonService.findOneEQ(GroupBuyingBaseEntity.class, findBase);
                    Integer durations = groupBuyingBase.getDuration();
                    groupbuyingTeam.setEndDatetime(DateUtil.addHours(new Date(), durations));
                    groupbuyingTeam.setNumParticipant(1);
                    if ((groupbuyingTeam.getNumParticipant()) == groupbuyingTeam.getNumMember()){
                        groupbuyingTeam.setSta(GroupBuyingConstant.TEAM_STA.SUCCESS);
                    }else{
                        groupbuyingTeam.setSta(GroupBuyingConstant.TEAM_STA.PENDING);
                    }
                    //消息抛出
                    GroupBuyingAutoCancelParamDto autoCancelParamDto = new GroupBuyingAutoCancelParamDto();
                    autoCancelParamDto.setGroupBuyingCode(groupBuyingBase.getCode());
                    autoCancelParamDto.setTeamCode(teamCode);
                    commonDao.merge(orderBase);
                    commonDao.merge(teamDetail);
                    commonDao.merge(groupbuyingTeam);
                    mnsUtil.putDelayMessageToQueue(QUEUE_GROUPBUYING_AUTO_CANCEL, JacksonUtil.beanToJson(autoCancelParamDto), durations * 60 * 60 + 5);//延迟5秒
                } else if ((groupbuyingTeam.getNumParticipant() + 1) == groupbuyingTeam.getNumMember()) {
                    groupbuyingTeam.setNumParticipant(groupbuyingTeam.getNumParticipant() + 1);
                    groupbuyingTeam.setSta(GroupBuyingConstant.TEAM_STA.SUCCESS);

                    commonDao.merge(orderBase);
                    commonDao.merge(teamDetail);
                    commonDao.merge(groupbuyingTeam);
                } else if ((groupbuyingTeam.getNumParticipant() + 1) > groupbuyingTeam.getNumMember()) {
                    GroupBuyingAutoRefundParamDto refundParamDto = new GroupBuyingAutoRefundParamDto();
                    refundParamDto.setGroupBuyingCode(groupBuyingCode);
                    refundParamDto.setTeamCode(teamCode);
                    refundParamDto.setOrderNo(orderBase.getOrderCode());
                    commonDao.merge(orderBase);
                    commonDao.merge(teamDetail);
                    commonDao.merge(groupbuyingTeam);
                    mnsUtil.putDelayMessageToQueue(QUEUE_GROUPBUYING_AUTO_REFUND, JacksonUtil.beanToJson(refundParamDto),1);//延迟
                } else {
                    groupbuyingTeam.setNumParticipant(groupbuyingTeam.getNumParticipant() + 1);
                    commonDao.merge(orderBase);
                    commonDao.merge(teamDetail);
                    commonDao.merge(groupbuyingTeam);
                }
            } finally {
                lock.unlock();
            }
        } else {
            throw new SysException(TEAMAUTO_CANCEL_ERROR, "当前操作阻塞,稍后重试");
        }
    }
}
